#include <vector>
#include <iostream>
#include <string>
#include <sstream>

namespace cxximpl
{
template <class Char>
using anystr =
    std::basic_string<Char, std::char_traits<Char>, std::allocator<Char>>;

template <class Char>
using anysstream =
    std::basic_stringstream<Char, std::char_traits<Char>, std::allocator<Char>>;

template <typename Char>
inline std::vector<anystr<Char>> split(anystr<Char> text, Char const delimiter)
{
    auto sstr = anysstream<Char>{text};
    auto tokens = std::vector<anystr<Char>>{};
    auto token = anystr<Char>{};
    while (std::getline(sstr, token, delimiter))
    {
        if (!token.empty())
            tokens.push_back(token);
    }

    return tokens;
}

template <typename Char>
inline std::vector<anystr<Char>> split(anystr<Char> text,
                                       anystr<Char> const& delimiters)
{
    auto tokens = std::vector<anystr<Char>>{};

    size_t pos, prev_pos = 0;
    while ((pos = text.find_first_of(delimiters, prev_pos)) !=
           std::string::npos)
    {
        if (pos > prev_pos)
            tokens.push_back(text.substr(prev_pos, pos - prev_pos));
        prev_pos = pos + 1;
    }

    if (prev_pos < text.length())
        tokens.push_back(text.substr(prev_pos, std::string::npos));

    return tokens;
}
}  // namespace cxximpl

using namespace std;
using namespace std::string_literals;

auto print = [](auto cont) {
    cout << cont.size() << " strings splited\n";
    for (auto const& s : cont)
    {
        cout << s << '\n';
    }
};

int main(int argc, char** argv)
{
    print(cxximpl::split("Hello world C++"s, ' '));
    print(cxximpl::split("This, is a test. Wow!"s, ".,! "s));
    return 0;
}